<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>api接口文档</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 0;
      background-color: #fcfcfc;
    }

    ::-webkit-scrollbar {
      width: 8px;
    }

    .doc-root {
      display: flex;
      height: 100vh;
      overflow: hidden;
    }

    .menu {
      box-sizing: border-box;
      width: 260px;
      height: 100vh;
      overflow-y: auto;
      padding: 10px;
      background-color: #fff;
      box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
    }

    .menu ul {
      list-style: none;
      padding: 0;
      margin: 0;
    }

    .menu li a {
      padding: 10px 0;
      padding-left: 10px;
    }

    .menu li a.active {
      color: #ef6820;
      background-color: #fdede4;
      border-radius: 5px;
    }

    .menu li a:hover {
      color: #007bff;
    }

    .menu li a {
      display: block;
      text-decoration: none;
      color: #333;
      cursor: pointer;
    }

    .menu .submenu {
      padding-left: 20px;
    }

    .doc-root-wrap {
      flex: 1;
      overflow: hidden;
      margin: 20px;
      padding: 20px;
      border-radius: 10px;
      background-color: #fff;
      box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
    }

    .doc-content-scroll-wrap {
      height: 100%;
      overflow-y: auto;
    }


    .search {
      margin-bottom: 20px;
    }

    .doc-title {
      display: flex;
      align-items: center;
      padding: 10px 0;
    }

    .doc-label,
    .doc-text {
      margin: 0;
    }

    /* 请求方法 */
    .methods-wrap {
      margin: 12px 0;
    }

    .methods {
      display: inline-block;
      padding: 4px 8px;
      margin: 0 4px;
      border-radius: 4px;
    }

    .methods.get {
      background-color: #e3f6ed;
      color: #17b26a;
    }

    .methods.post {
      background-color: #fdede4;
      color: #ef6820;
    }

    .methods.put {
      background-color: #e6f2fe;
      color: #2e90fa;
    }

    .methods.delete {
      background-color: #fde9e7;
      color: #f04438;
    }

    /*
    表格样式
    */
    .table-box {
      width: 100%;
    }

    .table-box table {
      border-collapse: collapse;
      display: table;
      width: 100%;
      text-align: center;
      border-spacing: 0;
    }

    .table-box table tr {
      border: 0;
      border-top: 1px solid #ddd;
      background-color: #fff;
    }

    .table-box table tr th {
      font-weight: 700;
      background-color: #eff3f5;
    }

    .table-box table tr td,
    .table-box table tr th {
      font-size: 14px;
      color: #4f4f4f;
      line-height: 22px;
      border: 1px solid #ddd;
      padding: 8px;
      word-break: normal !important;
      vertical-align: middle;
    }

    .table-box table tr:nth-child(2n) {
      background-color: #f7f7f7;
    }

    /* 表格样式完毕*/

    .code-wrap {
      padding: 16px;
      background-color: #fafafa;
    }

    .end {
      padding: 20px 0;
      text-align: center;
      color: #aaa;
    }
  </style>
</head>

<body>
  <div class="doc-root">
    <div class="menu">
      <h4>api列表</h4>
      <div class="search">
        <input type="text" id="searchInput" placeholder="搜索...">
        <button onclick="searchMenu()">搜索</button>
      </div>
      <div class="menu-wrap"><!-- menu slot --></div>
    </div>
    <div class="doc-root-wrap">
      <div class="doc-content-scroll-wrap">
        <div class="doc-inner-wrap">
          api接口文档
        </div>
        <div class="end">到底啦~</div>
      </div>
    </div>
  </div>
  <script>
    const menuList = document.querySelector(".menu-wrap") // menu渲染插槽
    const docWrap = document.querySelector(".doc-inner-wrap") // 文档渲染插槽

    function searchMenu() {
      const input = document.getElementById("searchInput").value.toLowerCase();
      const menuItems = menuList.getElementsByTagName("a");
      for (let i = 0; i < menuItems.length; i++) {
        const menuItem = menuItems[i];
        const menuItemText = menuItem.textContent.toLowerCase();
        if (menuItemText.includes(input)) {
          menuItem.style.display = "block";
          menuItem.parentNode.parentNode.style.display = "block"; // 显示父级子菜单
          menuItem.parentNode.parentNode.parentNode.style.display = "block"; // 显示父级父级菜单
        } else {
          menuItem.style.display = "none";
        }
      }
    }

    let docList = []
    fetch("./__doc__").then((res) => res.json()).then((res) => {
      docList = res.data || []
      renderMenu(docList)
    });

    function renderMenu(result) {
      menuList.innerHTML = buildMenu(result)
    }

    function menuClick(that, path) {
      document.querySelectorAll(".active").forEach(item => item.classList.remove("active"))
      that.classList.add("active")
      if (path) {
        renderDoc(docList.find(item => item.path === path))
      }
    }

    function renderDoc(docJson) {
      console.log(docJson);

      const methods = docJson.method.split('|').reduce((acc, item) => acc += `<div class="methods ${item.toLowerCase()}">${item}</div>`, '')
      const getTableData = (data, head = []) => {
        if (!data) return []
        const tableData = [head]
        Object.keys(data).forEach(key => {
          tableData.push([
            key,
            data[key].type,
            data[key].required ? '是<span style="color:red;">*</span>' : '否',
            data[key].desc
          ])
        })
        return tableData
      }
      const getResTableData = (data, head = []) => {
        if (!data) return []
        const tableData = [head]
        Object.keys(data).forEach(key => {
          tableData.push([
            key,
            data[key].type,
            data[key].desc
          ])
        })
        return tableData
      }
      const header = []
      const query = getTableData(docJson?.schema?.query, ['字段名', '类型', '是否必传', '描述'])
      const body = getTableData(docJson?.schema?.body, ['字段名', '类型', '是否必传', '描述'])
      const response = getResTableData(docJson?.schema?.response, ['字段名', '类型', '描述'])


      docWrap.innerHTML = `
          <div class="doc-title">
            <h5 class="doc-label">接口描述：</h5>
            <p class="doc-text">${docJson.desc}</p>
          </div>
          <div class="doc-title">
            <h5 class="doc-label">接口地址：</h5>
            <p class="doc-text">${docJson.path}</p>
          </div>
          <div class="doc-title">
            <h5 class="doc-label">接口状态：</h5>
            <p class="doc-text">${docJson.disabled ? '<span style="color:red;">已禁用</span>' : '<span style="color:#17b26a;">正常</span>'}</p>
          </div>
          <div class="methods-wrap">
            ${methods}
          </div>
          ${renderTable(header, '请求头（Header）参数：')}
          ${renderTable(query, 'url拼接参数：')}
          ${renderTable(body, '请求体（Body）参数：')}
          ${renderTable(response, '返回参数：')}
          <h5>返回示例：</h5>
          <pre class="code-wrap">
          <code class="language-json" style="user-select: text; position: unset;">
           {
           "code": 10002,
            "msg": "签名错误",
             "data": []
           }
          </code>
          </pre>
`
    }

    function renderTable(data, title) {
      if (!data || !data.length) return ''
      const tabldHead = `
          <thead>
            <tr>
             ${data[0].map(item => `<th>${item}</th>`).join('')}
            </tr>
          </thead>
        `

      const tableBody =
        `<tbody>
      ${data.slice(1).map(item =>
          `
          <tr>
          ${item.map(x => `<td>${x}</td>`).join('')}
          </tr>`
        ).join('')}
      </tbody>`

      return `
        <h5>${title}</h5>
        <div class="table-box">
          <table>
            ${tabldHead}
            ${tableBody}
          </table>
        </div>
      `
    }

    function buildMenu(routes) {
      const root = {};

      routes.forEach(route => {
        const parts = route.path.split('/').filter(Boolean);
        let current = root;

        for (let i = 0; i < parts.length; i++) {
          const part = parts[i];

          if (!current[part]) {
            current[part] = {};
          }

          // 如果是最后一级路径，则标记为叶子节点（包含 method）
          if (i === parts.length - 1) {
            current[part].__route__ = route;
          } else {
            current = current[part];
          }
        }
      })

      function renderTree(tree, depth = 0) {
        const keys = Object.keys(tree);
        let html = '';

        keys.forEach(key => {
          const node = tree[key];
          const isLeaf = !!node.__route__;
          const id = key.replace(/\//g, '-') + (isLeaf ? '' : '');
          const path = node.__route__ && node.__route__.path || ''

          html += '<li>';
          html += `<a data-path="${path}" onclick="menuClick(this,'${path}')">${key}</a>`;

          if (!isLeaf) {
            html += `<ul class="submenu">${renderTree(node, depth + 1)}</ul>`;
          }

          html += '</li>';
        });

        return html;
      }

      return '<ul id="menuList">' + renderTree(root) + '</ul>';
    }

    // function calcMenuData(routes) {
    //   const result = {}
    //   routes.forEach(route => {
    //     const paths = route.url.split('/').filter(Boolean) // 分割URL路径并过滤空值
    //     let current = result
    //     // 处理没有name属性的简单路由（如 {url: 'test'}）
    //     if (paths.length === 1) {
    //       current[paths[0]] = route
    //       return
    //     }
    //     // 处理多层路径
    //     for (let i = 0; i < paths.length; i++) {
    //       const path = paths[i]
    //       // 如果是最后一级且route有name属性，则使用name作为key
    //       if (i === paths.length - 1) {
    //         current[path] = route
    //       }
    //       // 如果是中间路径，则创建嵌套对象
    //       else {
    //         if (!current[path]) {
    //           current[path] = {}
    //         }
    //         current = current[path]
    //       }
    //     }
    //   })
    //   return result;
    // }
  </script>
</body>

</html>
